package cn.cnysa.spider.logic;

import cn.cnysa.spider.data.Property;
import cn.cnysa.spider.util.Log;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Memory_Leak
 *         Created by ireal on 15-7-2.
 */
public class Spider implements Runnable {
    private final static String SPIDER = "spider";
    private final static String PAGER_URL = "url";
    private final static String PAGER_ITEM = "item";
    private final static String PAGER_NEXT = "next";
    private final static String ORM = "orm";
    private final static String ORM_RESULT = "result";
    private final static String ORM_CLASS = "class";
    private final static String PROPERTY = "property";
    private final static String PROPERTY_NAME = "name";
    private final static String PROPERTY_SELECTOR = "selector";
    private Pager start = null;
    private OnResult onResult = null;

    private Spider() {
    }

    public static List<Spider> parseXml(String fileName) {
        InputStream inputStream = Spider.class.getClassLoader().getResourceAsStream(fileName);
        SAXReader xmlReader = new SAXReader();
        List<Spider> spiders = new ArrayList<Spider>();
        try {
            Document document = xmlReader.read(inputStream);
            Iterator<Element> elements = document.getRootElement().elements(SPIDER).iterator();
            while (elements.hasNext()) {
                Element element = elements.next();
                Spider spider = parse(element);
                if (spider == null)
                    continue;
                spiders.add(spider);
            }
        } catch (Exception e) {
            Log.w("filed to load config", e);
        }
        return spiders;
    }

    /**
     * 将xml元素解析为Spider对象
     */
    private static Spider parse(Element element) {
        String url = element.attributeValue(PAGER_URL);
        String item = element.attributeValue(PAGER_ITEM);
        String next = element.attributeValue(PAGER_NEXT);
        Element orm = element.element(ORM);
        String clazz = orm.attributeValue(ORM_CLASS);
        String result = orm.attributeValue(ORM_RESULT);
        Pager.Builder builder = new Pager.Builder();
        builder.url(url).next(next).clazz(clazz).items(item);
        Iterator<Element> properties = orm.elements(PROPERTY).iterator();
        while (properties.hasNext()) {
            Element property = properties.next();
            String name = property.attributeValue(PROPERTY_NAME);
            String selector = property.attributeValue(PROPERTY_SELECTOR);
            Property p = new Property(name, selector);
            builder.orm(p);
        }
        Spider spider = new Spider();
        spider.start = builder.build();
        spider.setOrmResult(result);
        return spider;
    }

    public void run() {
        try {
            do {
                runPage(start);
                start = start.next();
            } while (start != null);
        } catch (Exception e) {
            Log.e(e);
            e.printStackTrace();
        }
    }

    private void runPage(Pager pager) {
        try {
            pager.prepared();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Iterator<Object> objs = pager.items().iterator();
        while (objs.hasNext()) {
            Object o = objs.next();
            objs.remove();
            if (onResult == null)
                continue;
            else
                onResult.onEnum(o);
        }
    }

    private void setOrmResult(String clazz) {
        try {
            Class c = Class.forName(clazz);
            Object o = c.newInstance();
            if (o instanceof OnResult)
                onResult = (OnResult) o;
            else {
                String r = String.format("类%s没有继承OnResult接口", clazz);
                Log.e(r);
            }
        } catch (Exception e) {
            Log.e("Spider->setOrmResult", e);
            e.printStackTrace();
            return;
        }
    }

    public interface OnResult {
        void onEnum(Object o);
    }
}